package com.ruoyi.system.service.Evaluating.impl;

import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.system.controller.standard.SSEController;
import com.ruoyi.system.domain.Evaluating.EvaluationRecord;
import com.ruoyi.system.domain.Evaluating.EvaluationResult;
import com.ruoyi.system.domain.Evaluating.ExcelData;
import com.ruoyi.system.domain.EvaluationResultVo;
import com.ruoyi.system.domain.Indicator;
import com.ruoyi.system.domain.IndicatorEvaluationScoreVo;
import com.ruoyi.system.domain.IndicatorSystemData;
import com.ruoyi.system.domain.dto.StartEvaluationDto;
import com.ruoyi.system.domain.po.Report;
import com.ruoyi.system.domain.standard_relevant.Standard;
import com.ruoyi.system.domain.standard_relevant.StandardExcel;
import com.ruoyi.system.mapper.Evaluating.EvaluationResultMapper;
import com.ruoyi.system.service.Evaluating.IEvaluationRecordService;
import com.ruoyi.system.service.Evaluating.IEvaluationResultService;
import com.ruoyi.system.service.IIndicatorEvaluationScoreService;
import com.ruoyi.system.service.IIndicatorService;
import com.ruoyi.system.service.IIndicatorSystemDataService;
import com.ruoyi.system.service.report.IReportService;
import com.ruoyi.system.service.standard.IStandardExcelService;
import com.ruoyi.system.service.standard.IStandardService;
import com.ruoyi.system.util.ExcelReader;
import com.ruoyi.system.util.DataProcessUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Service
public class EvaluationProcessService {

    @Autowired
    private IIndicatorService indicatorService;

    @Autowired
    private IIndicatorSystemDataService indicatorSystemDataService;

    @Autowired
    private IIndicatorEvaluationScoreService indicatorEvaluationScoreService;

    @Autowired
    private IEvaluationResultService evaluationResultService;

    @Autowired
    private IReportService reportService;

    @Autowired
    private IEvaluationRecordService evaluationRecordService;

    @Autowired
    private IStandardExcelService standardExcelService;

    @Autowired
    private IStandardService standardService;

    @Autowired
    private SSEController sseController;

    private ExcelReader excelReader=new ExcelReader();

    /**
     * 整个模型的计算过程
     * @param startEvaluationDto
     * @return 标准的总评得分列表
     * @throws IOException
     */
    public CompletableFuture<Void> processTopsis(StartEvaluationDto startEvaluationDto) throws IOException, ExecutionException, InterruptedException {

        String username = SecurityUtils.getLoginUser().getUsername();

        return CompletableFuture.runAsync(() -> {
            try {
                //1、需要拿到前端返回的指标体系id找到该指标体系下的所有指标名称

                //2、需要拿到前端返回选中的标准列表的标准号的列表，::['ISO:9001','ISO 7055-2023','ISO 14001']
                //拿到三级指标列表
                List<Indicator> levelThrees = indicatorService.getBasicIndicatorsBySystemId(startEvaluationDto.getSystemId(), 3);
                if(levelThrees.size()==0){
                    sseController.sendMessage("没有三级指标！");
                }

                List<String> zhibiaoList = levelThrees.stream().map(Indicator::getIndicatorName).toList();

                //A11(参与国家影响力)---》A11
                zhibiaoList = DataProcessUtil.replaceElements(zhibiaoList);

                List<String> standardCodeList = List.of(startEvaluationDto.getStandardCodes());


                //0、根据standCodeList从数据库中拿到standExecl表中的数据。

                List<StandardExcel> standExcelList = standardExcelService.selectStandardExeclByStandardCodes(standardCodeList);
                if(standExcelList.size()==0){
                    sseController.sendMessage("没有标准数据！");
                }

                List<ExcelData> excelDataList = excelReader.convertToExcelDataList(standExcelList);
                ExcelData[] excelData = excelDataList.toArray(new ExcelData[0]);


                //获取指标id和指标名称的映射关系
                Map<Long, String> indicatorMap = levelThrees.stream()
                        .collect(Collectors.toMap(
                                Indicator::getId,
                                Indicator::getIndicatorName, // keyMapper - 从每个Indicator中提取用作键的属性
                                // valueMapper - 从每个Indicator中提取用作值的属性
                                (existing, replacement) -> existing, // mergeFunction - 如果有重复的键，则决定如何处理（这里选择保留原有的值）
                                LinkedHashMap::new           // mapSupplier - 指定返回的Map类型，这里使用LinkedHashMap以保持插入顺序
                        ));
                indicatorMap = DataProcessUtil.updateMapValues(indicatorMap);

                //1、计算主观权重
                //1、计算主观权重
                Map<String, Double> objectWeights = getObjectWeights(indicatorMap, zhibiaoList, startEvaluationDto.getSystemId());

                //2、计算客观权重
                Map<String, Double> subjectWeights = getSubjectWeights(excelData);
                //3、计算组合权重
                Map<String, Double> combinationWeights = getCombinationWeights(subjectWeights, objectWeights);
                //4、计算总评得分
                Map<String, Double> scores = calculateScroce(excelData, combinationWeights);

                //5、计算各指标得分
                ExcelData[] indicatorsScores = calculateIndicatorsScores(combinationWeights, scores);


                //万事具备，只剩写入数据库了


                //用于后续批量插入
                List<EvaluationResult> evaluationResults = new ArrayList<>();
                List<IndicatorEvaluationScoreVo> indicatorEvaluationScoreVoList = new ArrayList<>();
                List<Report>  reports = new ArrayList<>();

                // entry是每个<指标，得分>的对象

                for (Map.Entry<String, Double> entry : scores.entrySet()) {
                    EvaluationResult evaluationResult = new EvaluationResult();

                    //转化为long类型存数据库
                    evaluationResult.setOutputValue(entry.getValue().longValue());
                    //设置指标体系id和name
                    evaluationResult.setProjectId(startEvaluationDto.getSystemId());
                    evaluationResult.setProjectName(startEvaluationDto.getSystemName());
                    evaluationResult.setCreateUser(username);

                    //补充：写入标准号和标准名称
                    evaluationResult.setStandardCode(entry.getKey());
                    //额外借标准服务拿取了标准名称
//                    Standard tmp_standardVo = standardService.selectStandardByCode(entry.getKey());
//                    evaluationResult.setstandardName(tmp_standardVo.getStandardName());

                    //设置此次评价名称
                    evaluationResult.setEvaluationName(startEvaluationDto.getEvaluationName());
                    //设置评价日期
                    evaluationResult.setEvaluateDate(new Date());
                    //补充：默认设置为不公开
                    evaluationResult.setpublicStatus(0);
                    //后续再批量插入到数据库
                    evaluationResults.add(evaluationResult);
                    //从各指标得分数组拿到此标准的各指标得分indicatorsScores
                    for (ExcelData data : indicatorsScores) {
                        IndicatorEvaluationScoreVo indicatorEvaluationScoreVo = new IndicatorEvaluationScoreVo();
                        //各指标得分还得存到IndicatorEvaluationScore表里
                        if (data.getRowName().equals(entry.getKey())) {
//                            indicatorEvaluationScoreVo.setEvaluationId(evaluationResult.getId());
                            List<EvaluationResultVo> evaluationResultVos = getIndicatorEvaluationScoreVo(indicatorMap, combinationWeights, objectWeights, data);
                            indicatorEvaluationScoreVo.setIndicatorScore(evaluationResultVos);
                            indicatorEvaluationScoreVo.setUserName(username);
                            indicatorEvaluationScoreVoList.add(indicatorEvaluationScoreVo);
//                            indicatorEvaluationScoreService.insertIndicatorEvaluationScore(indicatorEvaluationScoreVo);
                        }
                    }

                    //写报告
                    Report report = new Report();
                    report.setReportName("测试" + entry.getKey() + "报告");
                    report.setReportContentPath("/path/to/content3");
                    report.setEvaluationResult(entry.getValue().floatValue());
                    report.setEvaluationDate(new Date());
                    report.setCreateTime(new Date());
                    report.setStandardCode(entry.getKey());
                    report.setCreateUser(username);
                    report.setEvaluationName(startEvaluationDto.getEvaluationMethodName());
                    reports.add(report);
//                    reportService.insertReport(report);
                }
                //开始调用数据库批量插入操作，需要在mapper层实现
                if(evaluationResults.size()>0){
                    evaluationResultService.batchInsert(evaluationResults);
                    // 获取批量插入后生成的ID并设置到indicatorEvaluationScoreVoList和reports中
                    Map<String, Long> standardCodeToIdMap = evaluationResults.stream()
                        .collect(Collectors.toMap(
                            EvaluationResult::getStandardCode,
                            EvaluationResult::getId
                        ));

                    for (IndicatorEvaluationScoreVo vo : indicatorEvaluationScoreVoList) {
                        String standardCode = vo.getIndicatorScore().get(0).getStandardCode();
                        vo.setEvaluationId(standardCodeToIdMap.get(standardCode));
                    }

                    for (Report report : reports) {
                        report.setEvaluationResultId(standardCodeToIdMap.get(report.getStandardCode()));
                    }
                }

                if (!indicatorEvaluationScoreVoList.isEmpty()) {
                    indicatorEvaluationScoreService.batchInsert(indicatorEvaluationScoreVoList);
                }
                if(reports.size()>0){
                    reportService.batchInsert(reports);
                }
//                for(IndicatorEvaluationScoreVo indicatorEvaluationScoreVo:indicatorEvaluationScoreVoList){
//                    indicatorEvaluationScoreService.insertIndicatorEvaluationScore(indicatorEvaluationScoreVo);
//                }
                //生成操作记录
                EvaluationRecord evaluationRecord = new EvaluationRecord();
                evaluationRecord.setEvaluationName(startEvaluationDto.getEvaluationMethodName());
                evaluationRecord.setEvaluationId(startEvaluationDto.getEvaluationMethodId());
                evaluationRecord.setProjectName(startEvaluationDto.getSystemName());
                evaluationRecord.setProjectId(startEvaluationDto.getSystemId().toString());
                evaluationRecord.setCreateUser(username);
                Long standNum = Long.valueOf(startEvaluationDto.getStandardCodes().length);
                evaluationRecord.setStandardNumber(standNum);
                evaluationRecordService.insertEvaluationRecord(evaluationRecord);
                sseController.sendMessage("评价成功");

            }catch (Exception e) {
                    sseController.sendMessage(e.toString());
                    throw new RuntimeException(e);

                }
            });

    }

    /**
     * 根据客观权重，主观权重，指标he指标idMap,一个ExcelData构建indicatorEvaluationScoreVo.setIndicatorScore();
     * @param
     * @return
     */
    public List<EvaluationResultVo> getIndicatorEvaluationScoreVo(Map<Long,String> indicatorMap,Map<String, Double> combinationWeights, Map<String, Double> subjectWeigths, ExcelData data) {
        List<EvaluationResultVo> evaluationResultVos = new ArrayList<>();
        for (Map.Entry<Long, String> entry : indicatorMap.entrySet()) {
            //根据指标id找到该指标的指标体系下的指标名称
            EvaluationResultVo evaluationResultVo=new EvaluationResultVo();
            evaluationResultVo.setIndicatorId(entry.getKey());
            evaluationResultVo.setObjectiveWeight(subjectWeigths.get(entry.getValue()).floatValue());
            evaluationResultVo.setCombinationWeight(combinationWeights.get(entry.getValue()).floatValue());
            int Scoreindex= IntStream.range(0, data.getColumnNames().length)
                    .filter(index -> data.getColumnNames()[index].equals(entry.getValue()))
                    .findFirst()
                    .getAsInt();
            Double score = data.getData()[Scoreindex];
            evaluationResultVo.setIndicatorName(getLabelMap(entry.getValue()));
            evaluationResultVo.setScore(score.floatValue());
            evaluationResultVo.setStandardCode(data.getRowName());
            evaluationResultVos.add(evaluationResultVo);
        }
        return evaluationResultVos;
    }
    public static String getLabelMap(String label) {
        Map<String, String> labelMap = new HashMap<>();
        labelMap.put("A11", "A11(参与国家影响力)");
        labelMap.put("A12", "A12(参与企业/组织影响力)");
        labelMap.put("A13", "A13(起草人员)");
        labelMap.put("B11", "B11(标准转化)");
        labelMap.put("B12", "B12(其他标准引用)");
        labelMap.put("B13", "B13(被法律法规引用)");
        labelMap.put("B14", "B14(其他工程应用)");
        labelMap.put("B21", "B21(标准传播)");
        labelMap.put("B22", "B22(认证认可)");
        labelMap.put("B23", "B23(标准关注度)");
        labelMap.put("B24", "B24(标准衍生材料传播)");
        labelMap.put("B31", "B31(标准引领性)");
        labelMap.put("B32", "B32(标准创新性)");
        labelMap.put("B33", "B33(标准获奖)");
        labelMap.put("B41", "B41(社会关注度)");
        labelMap.put("B42", "B42(可持续发展支撑度)");
        labelMap.put("B43", "B43(对外贸易应用(国际贸易影响))");
        labelMap.put("B44", "B44(产业扩散广度)");
        return labelMap.get(label);
    }
    //3、需要根据指标体系下指标计算主观权重列表，::[0.2, 0.4, 0.1]
    public Map<String, Double> getObjectWeights(Map<Long, String> originalMap,List<String> zhibiaoList,Long systemId) {
        // 计算主观权重列表
        //只有指标id,和主观权重，怎么构造这张Map("A1", 0.0612)
        List<IndicatorSystemData> indicatorSystemDataList = indicatorSystemDataService.selectIndicatorSystemDataBySystemId(systemId);
        Map<String, Double> originObjectWeights=new HashMap<>();
        for(String zhibiao : zhibiaoList){
            if(originalMap.containsValue(zhibiao)){
                //
                Long indicatorId=originalMap.entrySet().stream().filter(x -> x.getValue().equals(zhibiao)).findFirst().get().getKey();
                originObjectWeights.put(zhibiao,indicatorSystemDataList.stream().filter(x -> x.getIndicatorId().equals(indicatorId)).findFirst().get().getSubjectiveWeight().doubleValue());
            }
        }

        Map<String, Double> objectWeights = DataProcessUtil.objectWeights(originObjectWeights);

        return objectWeights;
    }
    //4、根据指标列表和标准列表计算客观权重列表，::[0.2, 0.4, 0.1]
    public Map<String, Double> getSubjectWeights(ExcelData[] excelData) {
        // 计算客观权重列表
        Map<String, Double> subjectWeights = DataProcessUtil.calculateGreyRelationalGrades(excelData);
        return subjectWeights;
    }

    //5、根据主观权重和客观权重计算组合权重
    public Map<String, Double> getCombinationWeights(Map<String, Double> subjectWeigths, Map<String, Double> objectWeigths) {
        // 计算组合权重列表
        Map<String, Double> combinationWeights = DataProcessUtil.combinationWeights(subjectWeigths, objectWeigths);
        //还要把权重存到指标和指标体系的中间表
        return combinationWeights;
    }
    //6、计算总评得分{ISO 9001:34,ISO 7055-2023:19}
    public Map<String, Double> calculateScroce(ExcelData[] data, Map<String,Double> conbinationWeigths) throws IOException {
        // 计算总评得分列表
        Map<String ,Double> scores = DataProcessUtil.calculateTopsis(data, conbinationWeigths);
        //还要把总评得分存到评价结果的表里
        return scores;
    }
    //7、根据组合权重计算各指标得分列表
    public ExcelData[] calculateIndicatorsScores(Map<String, Double> combinationWeigths, Map<String,Double> stardardsScore) {
        // 计算主观权重列表
        ExcelData[] indicatorsScores = DataProcessUtil.calculateIndicatorsScores(combinationWeigths, stardardsScore);
        return indicatorsScores;
    }

}
